…rect the stale sentence in the stack-refusal-envelopes changeset
The unconsumed changeset .changeset/stack-refusal-envelopes.md claimed that none
of the six new STACK_* codes is registered in ERROR_CODE_LEDGER. That sentence
was true when it was written and is false against main today: all seven STACK_*
codes -- the six plus the STACK_CROSS_REFERENCE_INVALID precedent -- are now
registered under the '@objectstack/spec' key of ERROR_CODE_LEDGER.
Measured on this tree, not inherited:
grep -n "STACK_" packages/spec/src/api/error-code-ledger.zod.ts
-> 7 rows, lines 1045-1051, inside the '@objectstack/spec' array (key at
line 1018; ERROR_CODE_LEDGER declared at line 176)
The paragraph's OTHER claim -- that no wire door raises these codes -- is
independent of the registration and survives re-measurement unchanged, so it is
kept verbatim:
grep -rn "defineStack" packages/rest/src/ -> exit 1, 0 occurrences
grep -rn "defineStack" packages/runtime/src/ -> 38 occurrences, 26 in
non-test files, every one a comment or docstring; 0 call sites, 0 imports
Both zero readings carry positive controls: the same invocation finds
refuseUnknownQueryParams in packages/rest/src (3 files) and finds defineStack
in packages/runtime/src, and an import-shaped grep for ApiErrorSchema over the
same two trees returns 25 lines.
One sentence, one file. The message text, the refusal table, the semver
argument and the "Not narrowed" framing are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
Fixes #16671
.changeset/stack-refusal-envelopes.mdis #16342's changeset, still unconsumed. Its "Not narrowed" paragraph carried this clause:It was true when it was written and is false against
maintoday. Both changesets compile into the same release, so the publishedCHANGELOG.mdwould ship a sentence that the very same release falsifies. One sentence, one file: 1 insertion, 1 deletion.What was measured on this tree
Worktree base
169215724; every reading below was taken here, not inherited from the card.1. Seven codes are registered, not zero — and the count in the card is confirmed
grep -n "STACK_" packages/spec/src/api/error-code-ledger.zod.tsreturns 7 rows, lines 1045–1051, sitting inside the'@objectstack/spec'array (key at line 1018;ERROR_CODE_LEDGERdeclared at line 176):STACK_CAPABILITY_UNKNOWNSTACK_CROSS_REFERENCE_INVALIDSTACK_HIERARCHY_SCOPE_CAPABILITY_REQUIREDSTACK_NAMESPACE_PREFIX_INVALIDSTACK_SCHEMA_INVALIDSTACK_SINGLE_APP_VIOLATIONSTACK_TRIGGER_CAPABILITY_REQUIREDSo it is all seven — the six new codes and the
STACK_CROSS_REFERENCE_INVALIDprecedent. The original sentence's frame ("none of the six … for the reason the precedent was not") is wrong on both halves, not one, which is why the replacement names seven rather than six.Provenance, read from git rather than from the card:
git log -S"STACK_TRIGGER_CAPABILITY_REQUIRED" -- packages/spec/src/api/error-code-ledger.zod.tsnames exactly one commit,abae16adf, whose subject is "feat(spec): register every error code that ships in dist — ninedoor: 'none'codes enterERROR_CODE_LEDGERunder the #16404 ruling (#16449) (#16652)". Card #16449, landed as PR #16652. The corrected sentence names both.2. The paragraph's OTHER claim is independent, and it survives
Registration in the ledger and "no wire door raises them" are different facts; only the first moved. Re-measured, with a positive control beside each zero:
grep -rn "defineStack" packages/rest/src/grep -rn "defineStack" packages/runtime/src/grep -rnE "import[^;]*defineStack" packages/runtime/src packages/rest/srcgrep -rln "refuseUnknownQueryParams" packages/rest/src/.tsfiles)grep -rnE "import[^;]*ApiErrorSchema" packages/rest/src packages/runtime/srcZero call sites, zero imports, both zeros controlled. The clause "no wire door raises them —
defineStackruns at authoring and boot time, and no HTTP domain handler calls it (re-measured: every non-testdefineStackoccurrence underpackages/runtime/srcandpackages/rest/srcis a docstring, a comment or the vocabulary table's own prose)" is therefore kept byte-for-byte, asserted by grep after the edit. The ledger's own comment on those rows records the same reading, so the registration corroborates the clause rather than displacing it — which is what the replacement says.3. The release window is still open
ls .changeset/*.mdminusREADME= 366 unconsumed changesets (the card's dispatch predicted 369;mainmoved between the two readings — not material, the window is open either way), and.changeset/stack-refusal-envelopes.mdis still among them.Does this PR need a changeset of its own? No — measured
The gate's own rule is "If it releases nothing … apply the
skip-changesetlabel", so this was decided on a measurement:packages/spec/src/api/error-code-ledger.zod.tsto exactly 1 directory, so the zero is a reading and not a broken check.@objectstack/spec-monorepo,private: true, nofiles[].@objectstack/spec'sfiles[]isdist,json-schema,liveness,prompts,llms.txt,README.md,src/**/*.zod.ts,CHANGELOG.md,api-surface,spec-changes.json— none of which reaches.changeset/.⇒ nothing in any released package's published
files[]moves.skip-changesetapplied.Worth stating explicitly because it looks like a counter-example: this diff does change text that will land in
packages/spec/CHANGELOG.md, which is infiles[]. It changes it as a release input already queued, not as a new release — that is the whole point of the deadline. Adding a changeset here would ship a CHANGELOG entry announcing a prose repair to another CHANGELOG entry in the same release.Gates
Derived mechanically rather than from the dispatch list:
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(it attests "gate list derived from the tree of 'objectstack-ai/objectstack' at commit 1692157").17 derived / 17 run / 17 exit 0 / 0 NOT-MEASURED / 0 UNRUN, reconciled with
--ran, which printedRun reconciliation — 17 derived, 17 run, 0 NOT-MEASURED, 0 UNRUN.Every exit code was captured into a variable before any pipe.Additionally run, because the derivation flagged it explicitly (⛔ "roster under .changeset, which one of your paths is in" — its silence is evidence in neither direction there):
node scripts/check-changeset-fixed.mjs→ exit 0,✓ .changeset/config.json "fixed" group is in sync with 70 public workspace packages.No repo-wide
pnpm lintnarrowing is claimed: this diff contains no lintable source file.pnpm check:nul-bytesis green, and a self-scangrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over the edited file returns 0 (positive control: the same pattern matches a\x0bbyte, exit 0 — note\x09is deliberately outside the class, so a tab is not a valid control here).验收备注 — out of scope, filed separately
The file's closing paragraph still says
@objectstack/runtime"carries one classification row per new code in the dispatcher error-code vocabulary (door: 'none',verdict: 'boot-refusal')". Measured:grep -n "code: 'STACK_" packages/runtime/src/dispatcher-error-vocabulary.ts→ exit 1, 0 rows. Positive controls in the same file with the same grep shape:verdict: 'boot-refusal'still returns 5 rows andcode: 'returns 65, so the zero is a reading. Commitabae16adf— the same commit that performed the registration corrected above — ratcheted those rows out; the file now carries only a comment about the removal at line 302. Registering the codes and removing the vocabulary rows were one landing, which is exactly why fixing only the first half leaves the paragraph visibly self-inconsistent to a reviewer.Nothing else was noted.
Generated by Claude Code